package com.acmen.easyapi.validation;

import com.acmen.easyapi.annotation.EnumValue;
import com.acmen.easyapi.annotation.ReqParam;
import com.acmen.easyapi.model.Dictionary;
import com.acmen.easyapi.provider.DictionaryProvider;
import com.acmen.easyapi.strategy.ReqParamStrategy;
import com.acmen.easyapi.util.ClassUtil;
import com.acmen.easyapi.util.EnumUtil;
import com.acmen.easyapi.util.SpringContextUtil;
import com.acmen.easyapi.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;


/**
 * 校验器
 *
 * @author acmen
 * @date 2022-03-08
 */
@Component
public abstract class AbstractValidator {
    @Resource
    protected ReqParamStrategy reqParamStrategy;
    @Resource
    protected DictionaryProvider dictionaryProvider;


    public List<Message> validate(Object data) {
        List<Message> messages = new ArrayList<Message>();  // 创建一个空的Message列表

        if (data == null) {  // 如果data为空
            return messages;  // 返回空的Message列表
        }

        if (data instanceof Collection) {  // 如果data是Collection的实例
            Collection collection = (Collection) data;  // 将data强制转换为Collection类型，并赋值给collection变量
            Iterator iterator = collection.iterator();  // 获取collection的迭代器，并赋值给iterator变量
            int idx = 0;  // 创建一个初始值为0的整数变量idx
            while (iterator.hasNext()) {  // 当iterator还有下一个元素时
                Object d = iterator.next();  // 获取iterator的下一个元素，并赋值给d变量
                if (d != null) {  // 如果d不为空
                    messages.addAll(validate(d, "[" + idx + "]"));  // 将validate函数验证得到的Message列表添加到messages列表中
                }
                idx++;  // idx加1
            }
            return messages;  // 返回验证得到的Message列表
        } else if (data.getClass().isArray()) {  // 否则，如果data是一个数组类
            return messages;  // 返回空的Message列表
        } else {  // 否则
            return validate(data, null);  // 调用validate函数对data进行验证，并返回验证得到的Message列表
        }

    }

    protected abstract List<Message> validate(Object data, String fieldNamePrefix);


    protected List<Message> validate(Object data, ReqParam reqParam, String fieldName) {
        List<Message> messages = new ArrayList<Message>();
        if (StringUtil.isEmpty(data)) {
            if (reqParam.required()) {
                messages.add(new Message(fieldName, "不能为空"));
            }
            return messages;
        }
        if(reqParam.enumClass().isEnum()&&validateEnumData(data, reqParam, fieldName, messages)){
            return messages;
        }
        if (data instanceof Collection) {
            Collection collection = (Collection) data;
            if (collection.isEmpty()) {
                if (reqParam.required()) {
                    messages.add(new Message(fieldName, "不能为空"));
                }
                return messages;
            }
            if (reqParam.maxLength() > 0 && collection.size() > reqParam.maxLength()) {
                messages.add(new Message(fieldName, "长度超过了" + reqParam.maxLength()));
            } else {
                Iterator iterator = collection.iterator();
                int idx = 0;
                boolean isEmpty = true;
                while (iterator.hasNext()) {
                    Object d = iterator.next();
                    if (StringUtil.isNotEmpty(d)) {
                        //校验数据格式
                        messages.addAll(validateDataFormat(d, fieldName + "[" + idx + "]", reqParam.validateExp()));
                        if (d instanceof Collection || d.getClass().isArray()) {
                            messages.addAll(validate(d, reqParam, fieldName + "[" + idx + "]"));
                        } else {
                            messages.addAll(validate(d, fieldName + "[" + idx + "]"));
                        }
                        isEmpty = false;
                    }
                    idx++;
                }
                if (reqParam.required() && isEmpty) {
                    messages.add(new Message(fieldName, "不能为空"));
                }
            }
        } else if (data.getClass().isArray()) {
            Object[] objects = (Object[]) data;
            int idx = 0;
            boolean isEmpty = true;
            for (Object d : objects) {
                if (StringUtil.isNotEmpty(d)) {
                    //校验数据格式
                    messages.addAll(validateDataFormat(d, fieldName + "[" + idx + "]", reqParam.validateExp()));
                    if (d instanceof Collection || d.getClass().isArray()) {
                        messages.addAll(validate(d, reqParam, fieldName + "[" + idx + "]"));
                    } else {
                        messages.addAll(validate(d, fieldName + "[" + idx + "]"));
                    }
                    isEmpty = false;
                }
                idx++;
            }
            if (reqParam.required() && isEmpty) {
                messages.add(new Message(fieldName, "不能为空"));
            }
        } else if (data instanceof String) {
            if (reqParam.maxLength() > 0 && ((String) data).length() > reqParam.maxLength()) {
                messages.add(new Message(fieldName, "长度超过了" + reqParam.maxLength()));
            } else if(StringUtil.isNotEmpty(reqParam.dictType())){
                Dictionary dict = dictionaryProvider.selectOne(reqParam.dictType(),String.valueOf(data));
                if(dict == null){
                    messages.add(new Message(fieldName, "["+data+"]不是有效的值"));
                }
            }else{
                //校验数据格式
                messages.addAll(validateDataFormat(data, fieldName, reqParam.validateExp()));
            }
        } else if (data instanceof Integer || data instanceof Float || data instanceof Double
                || data instanceof Short|| data instanceof BigDecimal) {
            Float longData;
            if(data instanceof BigDecimal){
                longData = ((BigDecimal)data).floatValue();
            }else{
                longData =Float.parseFloat(data.toString());
            }
            if (reqParam.min() != -Long.MAX_VALUE && longData < reqParam.min()) {
                messages.add(new Message(fieldName, "不能小于" + reqParam.min()));
            }
            if (reqParam.max() != Long.MAX_VALUE && longData > reqParam.max()) {
                messages.add(new Message(fieldName, "不能大于" + reqParam.max()));
            }
            messages.addAll(validateDataFormat(data, fieldName, reqParam.validateExp()));
        } else if (data instanceof Boolean) {
            //什么都不做，不代表以后我不做
        } else if (data instanceof Date || data instanceof LocalDateTime
                || data instanceof LocalDate) {
        } else {
            messages.addAll(validate(data, fieldName));
        }
        return messages;
    }


    /**
     * 校验枚举数据类型
     * @param data
     * @param reqParam
     * @param fieldName
     * @param messages
     * @return
     */
    protected boolean validateEnumData(Object data, ReqParam reqParam, String fieldName, List<Message> messages) {
        if(data instanceof Collection){
            int idx = 1;
            List<Integer> valids = new ArrayList<>();
            for(Object o : (Collection)data){
                boolean valid = isValidEnumValue(o, reqParam.enumClass());
                if(valid==false){
                    valids.add(idx);
                }
                idx ++;
            }
            if(!valids.isEmpty()){
                messages.add(new Message(fieldName, "第"+ StringUtils.join(valids,",") +"个数据无效"));
            }
        }else if(data.getClass().isArray()){
            Object[] objects = (Object[]) data;
            int idx = 1;
            List<Integer> valids = new ArrayList<>();
            for (Object o : objects) {
                boolean valid = isValidEnumValue(o, reqParam.enumClass());
                if(valid==false){
                    valids.add(idx);
                }
                idx ++;
            }
            if(!valids.isEmpty()){
                messages.add(new Message(fieldName, "第"+ StringUtils.join(valids,",") +"个数据是无效"));
            }
        }else{
            boolean valid = isValidEnumValue(data, reqParam.enumClass());
            if(valid==false){
                messages.add(new Message(fieldName, data+"不是有效的值"));
            }
        }
        return !messages.isEmpty();
    }

    /**
     *
     * @param data
     * @param enumClass
     * @return
     */
    private boolean isValidEnumValue(Object data, Class<?> enumClass) {
        Field[] fields = enumClass.getDeclaredFields();
        EnumValue enumValue = AnnotatedElementUtils.findMergedAnnotation(enumClass, EnumValue.class);
        if(enumValue!=null){
            for (Object enumObj : enumClass.getEnumConstants()) {
                if(Objects.equals(Objects.toString(data),Objects.toString(enumObj))){
                    return true;
                }
            }
        }
        for (Object enumObj : enumClass.getEnumConstants()) {
            Object value = EnumUtil.getEnumValue(enumObj,fields);
            if(Objects.equals(value,data)){
                return true;
            }
        }
        return false;
    }


    /**
     * 校验字符字段数据格式
     *
     * @param fieldValue
     * @param validateExp
     */
    protected List<Message> validateDataFormat(Object fieldValue, String fieldName, String validateExp) {
        if (StringUtil.isEmpty(validateExp)) {
            return new ArrayList<Message>();
        }
        validateExp = validateExp.trim();
        Map<String, DataTypeValidator> dataValidatorMap = SpringContextUtil.getBeansOfType(DataTypeValidator.class);
        String exp = validateExp;
        List<Message> messages = new ArrayList<Message>();
        dataValidatorMap.forEach((k, v) -> {
            if (v.matches(exp)) {
                List<String> msgs = new ArrayList<String>();
                v.validate(exp, fieldValue, msgs);
                msgs.forEach(msg -> {
                    messages.add(new Message(fieldName, msg));
                });
            }
        });
        return messages;
    }

    /**
     * 校验必录组
     *
     * @param obj
     * @param fields
     * @return
     */
    protected void validateRequireGroup(Object obj, List<Field> fields, String fieldNamePrefix, List<Message> messages) {
        Map<String, List<Field>> groupMap = new HashMap();
        for (Field field : fields) {
            ReqParam reqParam = reqParamStrategy.getReqParam(obj.getClass(),field);
            if (reqParam == null) {
                continue;
            }
            String group = reqParam.requiredGroup();
            if (StringUtil.isNotEmpty(group)) {
                if (!groupMap.containsKey(group)) {
                    groupMap.put(group, new ArrayList<Field>());
                }
                groupMap.get(group).add(field);
            }
        }
        groupMap:
        for (Map.Entry<String, List<Field>> entry : groupMap.entrySet()) {
            for (Field field : entry.getValue()) {
                Object fieldValue = ClassUtil.getFieldValue(obj, field);
                if (fieldValue != null) {
                    if(fieldValue instanceof Collection){
                        if(((Collection<?>) fieldValue).size()>0){
                            continue groupMap;
                        }
                    }else{
                        continue groupMap;
                    }
                }
            }
            String label = null;
            for (Field field : entry.getValue()) {
                ReqParam reqParam = reqParamStrategy.getReqParam(obj.getClass(),field);
                if (fieldNamePrefix != null) {
                    fieldNamePrefix += ".";
                } else {
                    fieldNamePrefix = "";
                }
                if (label == null) {
                    label = fieldNamePrefix + reqParam.label();
                } else {
                    label += ";" + reqParam.label();
                }
            }
            Message message = new Message(label, "至少有一项不为空");
            messages.add(message);
        }
    }

    /**
     * 创建异常回应
     *
     * @param messages
     * @return
     */
    public static String buildFailureMessage(List<Message> messages) {
        StringBuffer errorMsg = new StringBuffer();
        for (int idx = 0; idx < messages.size(); idx++) {
            Message message = messages.get(idx);
            if (idx > 0) {
                errorMsg.append(";\r\n");
            }
            String[] fieldNames = message.getFieldName().split(";");
            String fieldName = null;
            for (int i = 0; i < fieldNames.length; i++) {
                if (fieldName == null) {
                    fieldName = fieldNames[i];
                } else {
                    fieldName += "," + fieldNames[i];
                }
            }
            errorMsg.append((idx + 1) + "、" + fieldName + ":" + message.getMsg());
        }
        return errorMsg.toString();
    }
}
